package com.le.medium.class6;

import org.junit.Test;

import java.util.LinkedList;
import java.util.Queue;

/**
 * 双向链表节点结构和二叉树节点结构是一样的，如果你把last认为是left， next认为是next的话。
 * 给定一个搜索二叉树的头节点head，请转化成一条有序的双向链表，并返回链 表的头节点。
 */
public class Problem02_BSTtoDoubleLinkedList {

    public static class Node {
        public int val;
        Node left;
        Node right;

        public Node(int val) {
            this.val = val;
        }
    }

    public static Node convert(Node head){
        if (head == null){
            return null;
        }
        return process(head).start;
    }


    public static class ReturnType {
        public Node start;
        public Node end;

        public ReturnType(Node start, Node end) {
            this.start = start;
            this.end = end;
        }
    }

    // 使用树形dp套路
    // 左子树最左节点是链表头结点，当前节点衔接前后，右子树左右节点是链表尾结点
    public static ReturnType process(Node head) {
        if (head == null) {
            return new ReturnType(null, null);
        }
        ReturnType leftInfo = process(head.left);
        ReturnType rightInfo = process(head.right);
        if (leftInfo.end != null) {
            leftInfo.end.right = head;
        }
        head.left = leftInfo.end;
        head.right = rightInfo.start;
        if (rightInfo.start != null) {
            rightInfo.start.left = head;
        }
        return new ReturnType(
                leftInfo.start == null ? head : leftInfo.start,
                rightInfo.end == null ? head : rightInfo.end
        );
    }



    // 中序遍历二叉树
    public static void inOrderPrint(Node head){
        if (head == null){
            return;
        }
        inOrderPrint(head.left);
        System.out.print(head.val + "  ");
        inOrderPrint(head.right);
    }

    // 获取中序遍历二叉树的结果添加到队列
    public static void inOrder(Node head, Queue<Node> queue){
        if (head == null){
            return;
        }
        inOrder(head.left,queue);
        queue.offer(head);
        inOrder(head.right,queue);
    }

    // 获取二叉树中序遍历所有节点
    // left看做pre指针
    // right看做next指针
    // 重连链表
    public static Node convert2(Node head){
        if (head == null){
            return head;
        }
        Queue<Node> queue = new LinkedList<>();
        inOrder(head,queue);
        if (queue.isEmpty()){
            return head;
        }
        head = queue.poll();
        Node pre = head;
        pre.left = null;
        Node cur = null;
        while (!queue.isEmpty()){
            cur = queue.poll();
            pre.right = cur;
            cur.left = pre;
            pre = cur;
        }
        pre.right = null;
        return head;
    }

    // 打印双向链表
    public static void printDoubleLinkedList(Node head) {
        System.out.print("Double Linked List: ");
        Node end = null;
        while (head != null) {
            System.out.print(head.val + " ");
            end = head;
            head = head.right;
        }
        System.out.print("| ");
        while (end != null) {
            System.out.print(end.val + " ");
            end = end.left;
        }
        System.out.println();
    }

    @Test
    public void test(){
        Node head = new Node(5);
        head.left = new Node(2);
        head.right = new Node(9);
        head.left.left = new Node(1);
        head.left.right = new Node(3);
        head.left.right.right = new Node(4);
        head.right.left = new Node(7);
        head.right.right = new Node(10);
        head.left.left = new Node(1);
        head.right.left.left = new Node(6);
        head.right.left.right = new Node(8);

//        inOrderPrint(head);
//        Node convert = convert(head);
//        System.out.println(convert2.val);
//        printDoubleLinkedList(convert);
        Node convert2 = convert2(head);
        printDoubleLinkedList(convert2);
    }
}
